﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CodonSegDP;
using System.IO;
using System.Diagnostics;
using System.Threading;
using TripletSegmentationGUI;
using AlgorithmResult;
using SegGen;
using NativeMethodsNameSpase;
using System.Linq;
using PermutationCl;
using System.Text.RegularExpressions;

using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;

namespace TripletSegmentationGUI
{
    public partial class MainScreen : Form
    {
        FileInfo processingFile = null;
        long realFileLength = 0;
        long readTillNow = 0;
        DynamicProgrammingParamsUI dpAlgUI = new DynamicProgrammingParamsUI();
        GeneticAlgorithmParamsUI geAlgUI = new GeneticAlgorithmParamsUI();
        //DynamicProgrammingAlg DPalgorithm = null;
        DPAlg DPalgorithm = null;
        SegGenAlgorithm GAalgorithm = null;
        static MainScreen thisForm = null;
        String processingText = String.Empty;
        public MainScreen()
        {
            InitializeComponent();
            AttachParamsPanelToChoosenAlg();
            thisForm = this;
        }

        private void AttachParamsPanelToChoosenAlg()
        {
            if (GARadioButton.Checked)
            {
                ParamsPanel.Controls.Remove(dpAlgUI);
                ParamsPanel.Controls.Add(geAlgUI);

            }
            else
            {
                ParamsPanel.Controls.Remove(geAlgUI);
                ParamsPanel.Controls.Add(dpAlgUI);
            }
        }

    
        delegate void UpadateDynamicProgrammingProgressCB(object sender, progressEvent eventProgress);
        private void UpadateDynamicProgrammingProgress(object sender, progressEvent eventProgress)
        {
            if (this.InvokeRequired)
            {
                UpadateDynamicProgrammingProgressCB d = new UpadateDynamicProgrammingProgressCB(UpadateDynamicProgrammingProgress);
                this.Invoke(d, new object[] { sender,eventProgress });
                return;
            }
           
                int value = (int)(progressBar.Maximum * ((double)(readTillNow + eventProgress.Index) / (double)realFileLength));
               if(value<=progressBar.Maximum && progressBar.Value!=value)
               {
                   progressBar.Value = value;
                //   progressBar.Refresh();
                 progressLabel.Text = (progressBar.Value/100).ToString();
               //  progressLabel.Refresh();
               
            }
        }
        delegate void UpadateGeneticAlgProgressCB(object sender, progressEvent eventProgress);
        private void UpadateGeneticAlgProgress(object sender, progressEvent eventProgress)
        {
            if (this.InvokeRequired)
            {
                UpadateGeneticAlgProgressCB d = UpadateGeneticAlgProgress;
                this.Invoke(d, new object[] { sender, eventProgress });
                return;
            }
           
                int value = (int)(10000 * ((double)(eventProgress.Index) / (double)geAlgUI.MaxNumGenerationNumericUpDown.Value));
                if (progressBar.Value != value)
                {
                    progressBar.Value = value;
                    progressBar.Refresh();
                    progressLabel.Text = (progressBar.Value / 100).ToString();
                    progressLabel.Refresh();
                }
            
        }
        delegate void UpadateGeneticAlgIdividualCB(object sender, progressEvent eventProgress);
        private void UpadateGeneticAlgIdividualCreation(object sender, progressEvent eventProgress)
        {
            if (this.InvokeRequired)
            {
                UpadateGeneticAlgIdividualCB d = UpadateGeneticAlgIdividualCreation;
                this.Invoke(d, new object[] { sender, eventProgress });
                return;
            }

            //int value = (int)(10000 * ((double)(eventProgress.Index) / (double)geAlgUI.MaxNumGenerationNumericUpDown.Value));
            if (progressBar.Value != eventProgress.Index)
            {
                geAlgUI.IndividualCreatorprogressBar.Value = eventProgress.Index;
                geAlgUI.IndividualCreatorprogressBar.Refresh();
              //  progressLabel.Text = (progressBar.Value / 100).ToString();
               // progressLabel.Refresh();
            }

        }
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openfile = new OpenFileDialog())
            {
                openfile.DefaultExt = "FASTA";
                openfile.Filter = "Fasta format (*.FASTA)|*.FASTA|Algorithm results (*.res)|*.res|Text Files (*.txt)|*.txt|All files (*.*)|*.*";
            if (openfile.ShowDialog() == DialogResult.OK)
            {
               
                progressBar.Value = 0;
                processingFile = new FileInfo(openfile.FileName);
                if (processingFile.Extension == ".res")
                {
                    Result result = Load(openfile.FileName);
                    
                    SpawnResultView(result,null);
                }
                FilePathLabel.Text = String.Format("Loaded : {0}", processingFile.Name);
                FilePathLabel.ForeColor = Color.Green;
                    FilePathLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(177)));
                    using (var reader = new StreamReader(processingFile.FullName))
                    {
                var line = reader.ReadLine();
                if (string.IsNullOrEmpty(line))
                    return;

                long filelength = processingFile.Length;
               
                if (line.StartsWith(">"))
                {
                    filelength -= line.Length;
                    char[] splitParams = new char[3];
                    splitParams[0] = ':';
                    splitParams[1] = '|';
                    splitParams[2] = '>';
                    String[] nameParser = line.Split(splitParams);
                    if (nameParser != null)
                    {
                        DnaName.Text = "DNA :";
                        for(int i=0;i<nameParser.Length;++i)

                            DnaName.Text = " " + nameParser[i];
                    }
                }
                    }
                statusLabel.Text = String.Empty;
                StartButton.Enabled = true;
                this.Refresh();
                }
            }
        }

      
        private void StartProcessing()
        {
        //    try
         //   {
                int KByte = 1024;
                int MByte = KByte * 1024;
                char[] bytes = new char[MByte * 10];
                char[] trimParams = new char[10];
                trimParams[0] = '\n';
                trimParams[1] = ' ';
                trimParams[2]= '\r';
                Stopwatch sw = new Stopwatch();
                sw.Start();

                // FileStream fs = new FileStream(processingFile.FullName, FileMode.Open, FileAccess.Read);
                using (var reader = new StreamReader(processingFile.FullName))
                {
                var line = reader.ReadLine();
                if (string.IsNullOrEmpty(line))
                    return;
                long filelength = processingFile.Length;
                int readedSize = 0;
                if (line.StartsWith(">"))
                {
                    filelength -= line.Length;
                }
                else
                {
                    reader.BaseStream.Position = 0;
                }
                realFileLength = filelength;
                while (filelength > 0)
                {
                    if (filelength < bytes.Length)
                    {
                        readedSize = reader.Read(bytes, 0, (int)filelength);
                        processingText = new String(bytes).Trim(trimParams);
                       processingText=   processingText.Replace(System.Environment.NewLine, String.Empty);
                       processingText = processingText.Replace("\n", String.Empty);
                   //   processingText[filelength] = '\0';
                    //  processingText=String.Join("", Regex.Split(processingText, @"(?:\r\n|\n|\r)"));

                        if (DPRadioButton.Checked)
                        {
                            AnalyzeAndPrintDynamicProgramming(processingText);//System.Text.Encoding.ASCII.GetString(bytes,0, (int)filelength));
                        }
                        else
                        {
                            AnalyzeAndPrintGeneticAlgorithm(processingText);//System.Text.Encoding.ASCII.GetString(bytes,0, (int)filelength));

                        }
                        break;
                    }
                    else
                    {
                        readedSize = reader.Read(bytes, 0, bytes.Length);
                        processingText = new String(bytes).Trim(trimParams);
                        processingText = new String(bytes).Trim(trimParams);
                        processingText = processingText.Replace(System.Environment.NewLine, String.Empty);
                        processingText = processingText.Replace("\n", String.Empty);
                        if (DPRadioButton.Checked)
                        {
                            AnalyzeAndPrintDynamicProgramming(processingText);//System.Text.Encoding.ASCII.GetString(bytes));
                        }
                        else
                        {
                            AnalyzeAndPrintGeneticAlgorithm(processingText);//System.Text.Encoding.ASCII.GetString(bytes,0, (int)filelength));
                        }
                    }
                    filelength -= readedSize;
                    readTillNow += readedSize;
                }
                Console.WriteLine("Time: {0} ms", sw.ElapsedMilliseconds);
                reader.Close();
                }
       /*      }
           catch (Exception exc)
            {
                
                MessageBox.Show(exc.Message);
            }
           */
                Thread.CurrentThread.ExecutionContext.Dispose();
                GC.Collect();

        }

        
        
        delegate void AnalyzeAndPrintGeneticAlgorithmCB(String testString);
        private void AnalyzeAndPrintGeneticAlgorithm(string Text)
        {
          
            {
                try
                { 
                     GAalgorithm = new SegGenAlgorithm((double)((geAlgUI.CrossOverPercentValue.Value) / 100),
                       (double)((geAlgUI.MutationFractionPercentValue.Value) / 100),
                       (double)((geAlgUI.ReproductionFractionPercent.Value) / 100),
                       (int)geAlgUI.NumTopIndviduals.Value,
                       (int)geAlgUI.NumNuclInCodon.Value);
                  //   geAlgUI.setMaximumValueForProgresBar((int)geAlgUI.PopulationSize.Value);

                Population.ProgressHandler += new ProgressEventHandler(geAlgUI.UpadateGeneticAlgIdividualCreation);
                GAalgorithm.ProgressHandler += new ProgressEventHandler(this.UpadateGeneticAlgProgress);
                     Result algresult = GAalgorithm.startSegGen(Text,
                        (int)geAlgUI.MaxNumGenerationNumericUpDown.Value,
                        (int)geAlgUI.PopulationSize.Value,
                        (int)geAlgUI.MinNumCodonsInSegment.Value,(double)geAlgUI.alphanumericUpDown1.Value);
                     AlgorithmFinished(algresult);
                   
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "/n" + ex.StackTrace);
                }
            }
        }



        delegate void AnalyzeAndPrintCB(String testString);
        private  void AnalyzeAndPrintDynamicProgramming(String testString)
        {
         // try{

              /*
                DPalgorithm = new DynamicProgrammingAlg();
                DPalgorithm.ProgressHandler += new ProgressEventHandler(this.UpadateDynamicProgrammingProgress);
                Result algresult = DPalgorithm.TripletBounderiesSegmentator(testString, (int)dpAlgUI.MinNumCodonsInSegment.Value, (int)dpAlgUI.NumNuclInCodon.Value);
                AlgorithmFinished(algresult);
              */
              DPalgorithm = new DPAlg(testString, (int)dpAlgUI.MinNumCodonsInSegment.Value, (int)dpAlgUI.NumNuclInCodon.Value);
              DPalgorithm.ProgressHandler += new ProgressEventHandler(this.UpadateDynamicProgrammingProgress);
              Result algresult = DPalgorithm.TripletBounderiesSegmentator();
              AlgorithmFinished(algresult);
              DPalgorithm = null;

          //}
          //catch (Exception ex)
          //{
          //    MessageBox.Show(ex.Message + "/n" + ex.StackTrace);
          //}
              
        }
        delegate void AlgorithmFinishedCB(Result algresult);
        private void AlgorithmFinished(Result algresult)
        {
            if (this.InvokeRequired)
            {
                AlgorithmFinishedCB d = new AlgorithmFinishedCB(AlgorithmFinished);
                this.Invoke(d, new object[] { algresult });
                return;
            }
            //else
            IParameters param=null;
            OpenUserControl(true);
            statusLabel.Text = "Finished";
            progressBar.Value = 10000;
            progressBar.Refresh();
            progressLabel.Text = "100";
            FinishTimeLabel.Text = String.Format("Finish Time : {0} {1}", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString());
            int numCodons;
            var tableFrm = new TableUIFrm();
            {
            if (DPRadioButton.Checked && DPalgorithm != null)
            {
                tableFrm.Text = "Dynamic Programming Result";
                numCodons = (int)dpAlgUI.NumNuclInCodon.Value;
                param=FillDPParams();
            }
            else
            {
                tableFrm.Text = "Genetic Algorithm Results";
                numCodons = (int)geAlgUI.NumNuclInCodon.Value;
                param = FillGAParams();
            }

               algresult.Text = processingText;
                algresult.CodonSize = numCodons;
                SpawnResultView(algresult, param);
          /*
                AlgorithmResultView resultView = new AlgorithmResultView(algresult);
            tableFrm.Controls.Add(resultView);
            resultView.Dock = DockStyle.Fill;
        //     var t = Task.Factory.StartNew(() => tableFrm.ShowDialog());
                
         //       t.Wait();
                Thread staThread = new Thread(new ParameterizedThreadStart(myMethod));
                staThread.TrySetApartmentState(ApartmentState.STA);
                staThread.Start(tableFrm);
           * */
            }
        }

        private IParameters FillGAParams()
        {
            GAParameters param = new GAParameters();
            param.codonSize = (int)geAlgUI.NumNuclInCodon.Value;
            param.minSegSize = (int)geAlgUI.MinNumCodonsInSegment.Value;
            param.population=(int)geAlgUI.PopulationSize.Value;

            param.CrossOverPercentValue= (int)(geAlgUI.CrossOverPercentValue.Value);
            param.MutationFractionPercentValue= (int)(geAlgUI.MutationFractionPercentValue.Value);
           
           param.NumTopIndviduals= (int)geAlgUI.NumTopIndviduals.Value;
            
                  
           param.generations=(int)geAlgUI.MaxNumGenerationNumericUpDown.Value;
            param.alphanumericUpDown1=(double)geAlgUI.alphanumericUpDown1.Value;
            return param;
        }

        private IParameters FillDPParams()
        {
            DpParameters param= new DpParameters();
            param.codonSize =(int)dpAlgUI.NumNuclInCodon.Value;
            param.minSegSize = (int)dpAlgUI.MinNumCodonsInSegment.Value;

            return param;
        }
        private void SpawnResultView(Result result,IParameters param)
        {
            var tableFrm = new TableUIFrm();
            AlgorithmResultView resultView = new AlgorithmResultView(result, param);
            
            tableFrm.Controls.Add(resultView);
            resultView.Dock = DockStyle.Fill;
            Thread staThread = new Thread(new ParameterizedThreadStart(myMethod));
            staThread.TrySetApartmentState(ApartmentState.STA);
            staThread.Start(tableFrm);
        }
        private void myMethod(object objFrm)
        {
            Form frm = (Form)objFrm;
            frm.ShowDialog();
            frm.Dispose();
            frm = null;
            Thread.CurrentThread.ExecutionContext.Dispose();
            GC.Collect();
            
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Application.Exit();
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
           
            progressBar.Value = 0;
            if (processingFile != null)
            {
                GC.Collect();
                statusLabel.Text = "Started";
                startTimelabel.Text = String.Format("Start  Time : {0} {1}", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString());
                FinishTimeLabel.Text = "FiniSh Time : --/--/--  --:--";
                progressLabel.Text = "0";
                OpenUserControl(false);

                Thread processThread = new Thread(new ThreadStart(StartProcessing));
                processThread.IsBackground = true;
                processThread.TrySetApartmentState (ApartmentState.STA);
                processThread.Start();

               //  AlgorithmBackgroundWorker.RunWorkerAsync();
              }
              

          
    
        }

      

        private void OpenUserControl(bool isOpened)
        {
            StartButton.Enabled = isOpened;
            StopButton.Enabled = !isOpened;
            SegmentationMethodGroupBox.Enabled = isOpened;
            ParamsPanel.Enabled = isOpened;
        }

     

        private void GARadioButton_CheckedChanged(object sender, EventArgs e)
        {
            AttachParamsPanelToChoosenAlg();
        }

        private void DPRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            AttachParamsPanelToChoosenAlg();
        }

        private void debugToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (debugToolStripMenuItem.Checked)
            {
                NativeMethodsNameSpase.NativeMethods.AllocConsole();
                NativeMethods.EnableCloseButton();
                Console.WriteLine("Debug Console");
            }
            else {
                NativeMethods.FreeConsole();
            }
        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (DPRadioButton.Checked && DPalgorithm != null)
                {

                    DPalgorithm.NeedToStop = true;

                }
                else if (GARadioButton.Checked && GAalgorithm != null)
                {
                    GAalgorithm.stopSegGen();
                }
                MessageBox.Show("Algorithm is stopping running ...");
            }
            catch (Exception exc)
            {

                MessageBox.Show(exc.Message, "/n" + exc.StackTrace);
            }
        }

        private void AlgorithmBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            StartProcessing();
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                using (Process notePad = new Process())
                {
                notePad.StartInfo.FileName = "clustalx";
                //  notePad.StartInfo.Arguments = "ProcessStart.cs";

                notePad.Start();
            }
            }
            catch (Exception exc)
            {
                
                MessageBox.Show( exc.Message);
            }
        }


        /// <summary>
        ///  Save the results of algorithm
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>


        static Result Load(string fileName)
        {
            Stream stream = null;
            Result result = null;
            try
            {
                IFormatter formatter = new BinaryFormatter();
                stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
                // int version = (int)formatter.Deserialize(stream);
                // Debug.Assert(version == VERSION);
                result = (Result)formatter.Deserialize(stream);
            }
            catch
            {
                // do nothing, just ignore any possible errors
            }
            finally
            {
                if (null != stream)
                    stream.Close();
            }
            return result;
        }

        private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
           
            //t.Wait();
        }

        private void DebugDynamicParams()
        {
            TableUIFrm.isDebug = true;
            for (int i = 3; i <= 10; i++)
            {
                dpAlgUI.MinNumCodonsInSegment.Value = i;
                for (int j = 3; j <= 10; ++j)
                {
                    dpAlgUI.NumNuclInCodon.Value = j;
                    dpAlgUI.Refresh();
                    StartProcessing();

                }
            }
        }
        private void DebugGeneticParams()
        {
            TableUIFrm.isDebug = true;
            for (int a = 2; a <= 100; a+=2)
            {
                
                (geAlgUI.alphanumericUpDown1.Value) = new decimal(new int[] {
            a,
            0,
            0,
            131072}); ;
                for (int i = 3; i <= 10; i++)
                {
                    geAlgUI.MinNumCodonsInSegment.Value = i;
                    for (int j = 3; j <= 10; ++j)
                    {
                        geAlgUI.NumNuclInCodon.Value = j;

                        for (int k = 2; k <= 1000; k += 10)
                        {
                            geAlgUI.NumTopIndviduals.Value = k;
                            for (int z = 10; z <= 1000; z += 100)
                            {

                                geAlgUI.PopulationSize.Value = z;

                                for (int x = 10; x <= 1000; x += 100)
                                {
                                    geAlgUI.MaxNumGenerationNumericUpDown.Value = x;
                                    geAlgUI.Refresh();
                                    StartProcessing();
                                }
                            }
                        }
                    }
                }
            }
        }
        private void dynamicToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var t = Task.Factory.StartNew(() => DebugDynamicParams());
        }

        private void geneticToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var t = Task.Factory.StartNew(() => DebugGeneticParams());
        }



       
    }
}
